import {
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import { produce, setAutoFreeze } from 'immer'
import useWebSocket, { ReadyState } from 'react-use-websocket'
import { useWorkflowRun } from '../../hooks'
import { NodeRunningStatus, WorkflowRunningStatus } from '../../types'
import { useWorkflowStore } from '@/app/components/workflow/store'
import type {
  ChatItem,
  Inputs,
  PromptVariable,
} from '@/app/components/base/chat/types'
import { useToastContext } from '@/app/components/base/toast'
import { TransferMethod } from '@/types/app'
import type { VisionFile } from '@/types/app'
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
import { API_PREFIX } from '@/config'

type GetAbortController = (abortController: AbortController) => void
type SendCallback = {
  onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
}
export const useChat = (
  data: any,
  config: any,
  promptVariablesConfig?: {
    inputs: Inputs
    promptVariables: PromptVariable[]
  },
  prevChatList?: ChatItem[],
  stopChat?: (taskId: string) => void,
) => {
  const token: any = localStorage.getItem('console_token')
  const workflowStore = useWorkflowStore()
  const { t } = useTranslation()
  const { notify } = useToastContext()
  const { handleRun } = useWorkflowRun()
  const hasStopResponded = useRef(false)
  const connversationId = useRef('')
  const taskIdRef = useRef('')
  const [chatList, setChatList] = useState<ChatItem[]>(prevChatList || [])
  const chatListRef = useRef<ChatItem[]>(prevChatList || [])
  const [isResponding, setIsResponding] = useState(false)
  const isRespondingRef = useRef(false)
  const [suggestedQuestions, setSuggestQuestions] = useState<string[]>([])
  const suggestedQuestionsAbortControllerRef = useRef<AbortController | null>(null)
  const [socketUrl, setSocketUrl] = useState('')
  const [isworkflowAnswer, setIsworkflowAnswer] = useState(false)
  const [workflowFinished, setWorkflowFinish] = useState(false)
  // const [messageHistory, setMessageHistory] = useState<MessageEvent<any>[]>([])
  const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl)
  console.log(chatList, 'chatList')
  console.log(lastMessage, 'lastMessage')
  console.log(workflowStore, 'workflowStore')
  const connectionStatus = {
    [ReadyState.CONNECTING]: 'Connecting',
    [ReadyState.OPEN]: 'Open',
    [ReadyState.CLOSING]: 'Closing',
    [ReadyState.CLOSED]: 'Closed',
    [ReadyState.UNINSTANTIATED]: 'Uninstantiated',
  }[readyState]

  const handleUpdateChatList = useCallback((newChatList: ChatItem[]) => {
    setChatList(newChatList)
    chatListRef.current = newChatList
  }, [])

  const blobToString = (msg: string) => {
    // const reader = new FileReader()
    // reader.readAsText(blob, 'utf-8')
    // reader.onload = function (e) {
    //   const newList: any = [...chatList]
    //   newList[newList.length - 1].content = reader.result
    //   console.log(newList, 'newList222')
    //   handleUpdateChatList(newList)
    // }
    const msgData = JSON.parse(msg)
    setIsworkflowAnswer(msgData.type !== 'multi_agent_output')
    const newList: any = [...chatList]
    newList[newList.length - 1].content = msgData.data
    handleUpdateChatList(newList)
  }

  const handleResponding = useCallback((isResponding: boolean) => {
    setIsResponding(isResponding)
    isRespondingRef.current = isResponding
  }, [])

  const handleWorkflowFinish = useCallback((isfinish: boolean) => {
    setWorkflowFinish(isfinish)
  }, [])

  useEffect(() => {
    console.log(connectionStatus)
    setAutoFreeze(false)
    if (data)
      // setSocketUrl(`//10.3.231.29:5002/console/api/apps/${data.id}/ws/metabolic?_token=${token}`)
      setSocketUrl(`${API_PREFIX}/apps/${data.id}/ws/metabolic?_token=${token}`)

    if (lastMessage !== null) {
      // 改造时先在这里判断ws的返回值是消息类型还是run接口类型
      // 同时拿到ws和run返回值后，判断是否是run接口返回的workflow类型（ws是!workflow，run接口类型是workflow），如果是则直接调用blobToString更新chatList
      // 而如果是run返回值后，传参给handleRun函数
      // 再去use-workflow-run的handleRun里面去改造ssPost函数，也添加一个传参（run的值），最终去更新base文件内的ssPost函数里面的handleStream
      // 让handleStream去更新重新拼接后的bufferObj，实现功能改造
      blobToString(lastMessage?.data)
      handleResponding(false)
      // setMessageHistory(prev => prev.concat(lastMessage))
      // console.log(messageHistory)
    }

    return () => {
      setAutoFreeze(true)
    }
  }, [data, lastMessage, readyState])

  const getIntroduction = useCallback((str: string) => {
    return replaceStringWithValues(str, promptVariablesConfig?.promptVariables || [], promptVariablesConfig?.inputs || {})
  }, [promptVariablesConfig?.inputs, promptVariablesConfig?.promptVariables])
  useEffect(() => {
    if (config?.opening_statement) {
      handleUpdateChatList(produce(chatListRef.current, (draft) => {
        const index = draft.findIndex(item => item.isOpeningStatement)

        if (index > -1) {
          draft[index] = {
            ...draft[index],
            content: getIntroduction(config.opening_statement),
            suggestedQuestions: config.suggested_questions,
          }
        }
        else {
          draft.unshift({
            id: `${Date.now()}`,
            content: getIntroduction(config.opening_statement),
            isAnswer: true,
            isOpeningStatement: true,
            suggestedQuestions: config.suggested_questions,
          })
        }
      }))
    }
  }, [config?.opening_statement, getIntroduction, config?.suggested_questions, handleUpdateChatList])

  const handleStop = useCallback(() => {
    hasStopResponded.current = true
    handleResponding(false)
    // if (stopChat && taskIdRef.current)
    //   stopChat(taskIdRef.current)

    if (suggestedQuestionsAbortControllerRef.current)
      suggestedQuestionsAbortControllerRef.current.abort()
  }, [handleResponding])

  const handleRestart = useCallback(() => {
    connversationId.current = ''
    taskIdRef.current = ''
    handleStop()
    const newChatList = config?.opening_statement
      ? [{
        id: `${Date.now()}`,
        content: config.opening_statement,
        isAnswer: true,
        isOpeningStatement: true,
        suggestedQuestions: config.suggested_questions,
      }]
      : []
    handleUpdateChatList(newChatList)
    setSuggestQuestions([])
  }, [
    config,
    handleStop,
    handleUpdateChatList,
  ])

  const updateCurrentQA = useCallback(({
    responseItem,
    questionId,
    placeholderAnswerId,
    questionItem,
  }: {
    responseItem: ChatItem
    questionId: string
    placeholderAnswerId: string
    questionItem: ChatItem
  }) => {
    console.log(responseItem,
      questionId,
      placeholderAnswerId,
      questionItem, 'updateCurrentQA')

    const newListWithAnswer = produce(
      chatListRef.current.filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
      (draft) => {
        if (!draft.find(item => item.id === questionId))
          draft.push({ ...questionItem })

        draft.push({ ...responseItem })
      })
    handleUpdateChatList(newListWithAnswer)
  }, [handleUpdateChatList])

  const handleSend = useCallback((
    params: any,
    {
      onGetSuggestedQuestions,
    }: SendCallback,
  ) => {
    console.log('send', workflowFinished)
    if (isRespondingRef.current) {
      notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
      return false
    }

    if (connectionStatus === 'Closed') {
      notify({ type: 'error', message: '连接断开，请刷新页面' })
      return false
    }

    const questionId = `question-${Date.now()}`
    const questionItem = {
      id: questionId,
      content: params.query,
      isAnswer: false,
      message_files: params.files,
    }

    const placeholderAnswerId = `answer-placeholder-${Date.now()}`
    const placeholderAnswerItem = {
      id: placeholderAnswerId,
      content: '',
      isAnswer: true,
    }

    const newList = [...chatListRef.current, questionItem, placeholderAnswerItem]
    console.log('newList', newList)
    handleUpdateChatList(newList)

    // answer
    const responseItem: ChatItem = {
      id: placeholderAnswerId,
      content: '',
      agent_thoughts: [],
      message_files: [],
      isAnswer: true,
    }
    console.log(responseItem, 'responseItem')


    handleResponding(true)

    const bodyParams = {
      conversation_id: connversationId.current,
      ...params,
    }
    if (bodyParams?.files?.length) {
      bodyParams.files = bodyParams.files.map((item: VisionFile) => {
        if (item.transfer_method === TransferMethod.local_file) {
          return {
            ...item,
            url: '',
          }
        }
        return item
      })
    }

    let hasSetResponseId = false
    if (newList.length === 2 || workflowFinished) {
      // 对话聊天的入口，调用组件的handleRun方法
      handleRun(
        params,
        {
          onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
            responseItem.content = responseItem.content + message
            console.log('onData')
            if (messageId && !hasSetResponseId) {
              responseItem.id = messageId
              hasSetResponseId = true
            }

            if (isFirstMessage && newConversationId)
              connversationId.current = newConversationId

            taskIdRef.current = taskId
            if (messageId)
              responseItem.id = messageId

            updateCurrentQA({
              responseItem,
              questionId,
              placeholderAnswerId,
              questionItem,
            })
          },
          async onCompleted(hasError?: boolean, errorMessage?: string) {
            console.log('onCompleted')
            handleResponding(false)

            if (hasError) {
              if (errorMessage) {
                responseItem.content = errorMessage
                responseItem.isError = true
                const newListWithAnswer = produce(
                  chatListRef.current.filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
                  (draft) => {
                    if (!draft.find(item => item.id === questionId))
                      draft.push({ ...questionItem })

                    draft.push({ ...responseItem })
                  })
                handleUpdateChatList(newListWithAnswer)
              }
              return
            }

            if (config?.suggested_questions_after_answer?.enabled && !hasStopResponded.current && onGetSuggestedQuestions) {
              const { data }: any = await onGetSuggestedQuestions(
                responseItem.id,
                newAbortController => suggestedQuestionsAbortControllerRef.current = newAbortController,
              )
              setSuggestQuestions(data)
            }
          },
          onMessageEnd: (messageEnd) => {
            console.log('onMessageEnd')
            responseItem.citation = messageEnd.metadata?.retriever_resources || []

            // const newListWithAnswer = produce(
            //   chatListRef.current.filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
            //   (draft) => {
            //     if (!draft.find(item => item.id === questionId))
            //       draft.push({ ...questionItem })

            //     draft.push({ ...responseItem })
            //   })
            // handleUpdateChatList(newListWithAnswer)
          },
          onMessageReplace: (messageReplace) => {
            console.log('onMessageReplace')
            responseItem.content = messageReplace.answer
          },
          onError() {
            console.log('onError')
            handleResponding(false)
          },
          onWorkflowStarted: ({ workflow_run_id, task_id }) => {
            console.log('onWorkflowStarted')
            taskIdRef.current = task_id
            responseItem.workflow_run_id = workflow_run_id
            responseItem.workflowProcess = {
              status: WorkflowRunningStatus.Running,
              tracing: [],
            }
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.findIndex(item => item.id === responseItem.id)
            //   draft[currentIndex] = {
            //     ...draft[currentIndex],
            //     ...responseItem,
            //   }
            // }))
          },
          onWorkflowFinished: ({ data }) => {
            handleWorkflowFinish(true)
            console.log('onWorkflowFinished')
            responseItem.workflowProcess!.status = data.status as WorkflowRunningStatus
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.findIndex(item => item.id === responseItem.id)
            //   draft[currentIndex] = {
            //     ...draft[currentIndex],
            //     ...responseItem,
            //   }
            // }))
          },
          onIterationStart: ({ data }) => {
            console.log('onIterationStart')
            responseItem.workflowProcess!.tracing!.push({
              ...data,
              status: NodeRunningStatus.Running,
              details: [],
            } as any)
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.findIndex(item => item.id === responseItem.id)
            //   draft[currentIndex] = {
            //     ...draft[currentIndex],
            //     ...responseItem,
            //   }
            // }))
          },
          onIterationNext: ({ data }) => {
            console.log('onIterationNext')
            const tracing = responseItem.workflowProcess!.tracing!
            const iterations = tracing.find(item => item.node_id === data.node_id
              && (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id))!
            iterations.details!.push([])

            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.length - 1
            //   draft[currentIndex] = responseItem
            // }))
          },
          onIterationFinish: ({ data }) => {
            console.log('onIterationFinish')
            const tracing = responseItem.workflowProcess!.tracing!
            const iterationsIndex = tracing.findIndex(item => item.node_id === data.node_id
              && (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id))!
            tracing[iterationsIndex] = {
              ...tracing[iterationsIndex],
              ...data,
              status: NodeRunningStatus.Succeeded,
            } as any
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.length - 1
            //   draft[currentIndex] = responseItem
            // }))

          },
          onNodeStarted: ({ data }) => {
            console.log('onNodeStarted')
            if (data.iteration_id)
              return

            responseItem.workflowProcess!.tracing!.push({
              ...data,
              status: NodeRunningStatus.Running,
            } as any)
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.findIndex(item => item.id === responseItem.id)
            //   draft[currentIndex] = {
            //     ...draft[currentIndex],
            //     ...responseItem,
            //   }
            // }))
          },
          onNodeFinished: ({ data }) => {
            console.log('onNodeFinished')
            if (data.iteration_id)
              return

            const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
              if (!item.execution_metadata?.parallel_id)
                return item.node_id === data.node_id
              return item.node_id === data.node_id && (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id)
            })
            responseItem.workflowProcess!.tracing[currentIndex] = {
              ...(responseItem.workflowProcess!.tracing[currentIndex]?.extras
                ? { extras: responseItem.workflowProcess!.tracing[currentIndex].extras }
                : {}),
              ...data,
            } as any
            // handleUpdateChatList(produce(chatListRef.current, (draft) => {
            //   const currentIndex = draft.findIndex(item => item.id === responseItem.id)
            //   draft[currentIndex] = {
            //     ...draft[currentIndex],
            //     ...responseItem,
            //   }
            // }))
          },
        },
      )
    }
    // websocket
    sendMessage(params.query)
    console.log(params.query, 'params.query')
  }, [handleRun, handleResponding, handleUpdateChatList, notify, t, updateCurrentQA,
    config.suggested_questions_after_answer?.enabled, handleWorkflowFinish, workflowFinished, readyState])

  return {
    conversationId: connversationId.current,
    chatList,
    handleSend,
    handleStop,
    handleRestart,
    isResponding,
    suggestedQuestions,
    isworkflowAnswer,
  }
}
